package nimy.info.android.dinnertime.page;

import info.nimy.google.recipesearch.html.RecipeItem;
import info.nimy.google.recipesearch.html.RecipeSearchResponse;

import java.io.InputStreamReader;
import java.text.MessageFormat;
import java.util.List;

import nimy.info.android.dinnertime.Constants;
import nimy.info.android.dinnertime.HomeActivity;
import nimy.info.android.dinnertime.connectivity.LoaderState;
import nimy.info.android.dinnertime.connectivity.ResponseObject;
import nimy.info.android.dinnertime.connectivity.ResponseParser;
import nimy.info.android.dinnertime.connectivity.WebConnector;
import nimy.info.android.dinnertime.data.RecipeItemCache;
import nimy.info.android.dinnertime.exception.ApplicationException;
import nimy.info.android.dinnertime.model.RecipeKeyword;
import nimy.info.android.dinnertime.utils.Utils;

import org.apache.http.HttpStatus;

import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.content.AsyncTaskLoader;
import android.util.Log;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.stream.JsonReader;

/**
 * 
 * @author 234aini@gmail.com 2012-10-29
 * 
 */
public class RecipeItemLoader extends
		AsyncTaskLoader<LoaderState<List<RecipeItem>>> {
	private static final String TAG = RecipeItemLoader.class.getName();

	private final static String RECIPE_SEARCH_URL = Utils.getProperty(
			Constants.CONFIG.RECIPE.key(), "");
	private RecipeItemCache mCache;
	private RecipeKeyword mKeyword;

	public RecipeItemLoader(Context context, Bundle bundle) {
		super(context);
	}

	/**
	 * 
	 * @param keyword
	 */
	public void pleaseLoad(final RecipeKeyword keyword) {
		this.mKeyword = keyword;
		startLoading();
	}

	@Override
	protected void onStartLoading() {
		if (isAbandoned()) {
			return;
		}
		if (mKeyword == null) {
			return;
		}
		forceLoad();
	}

	@Override
	public void deliverResult(LoaderState<List<RecipeItem>> loaderResult) {
		if (loaderResult.getData() != null) {
			getCache().put(mKeyword, loaderResult.getData());
		}
		if (isReset() || isAbandoned()) {
			// just save data to cache
			releaseResources();
		}
		if (isStarted()) {
			super.deliverResult(loaderResult);
		}
	}

	protected void onReset() {
		super.onReset();

		// Ensure the loader is stopped
		onStopLoading();

		// At this point we can release the resources associated with 'apps'
		// if needed.
		releaseResources();
	}

	private void releaseResources() {
		// TODO only release resource used by this loader instance
	}

	@Override
	public LoaderState<List<RecipeItem>> loadInBackground() {
		String url = MessageFormat.format(RECIPE_SEARCH_URL,
				Uri.encode(mKeyword.getName()), getStartIndex());
		if (HomeActivity.DEBUG) {
			Log.d(TAG, "Try to fetch data from url: " + url);
		}
		try {
			WebConnector<List<RecipeItem>> connector = WebConnector
					.getConnector(getContext(), url,
							new ResponseParser<List<RecipeItem>>() {
								@Override
								public List<RecipeItem> parse(
										ResponseObject response)
										throws ApplicationException {
									if (response.getStatusCode() == HttpStatus.SC_OK) {
										GsonBuilder gsonb = new GsonBuilder();
										Gson gson = gsonb.create();
										RecipeSearchResponse fromJson = gson
												.fromJson(
														new JsonReader(
																new InputStreamReader(
																		response.getInputStream())),
														RecipeSearchResponse.class);
										Log.d(TAG, fromJson.toString());
										return fromJson.getRecipes();
									} else {
										throw new ApplicationException(
												"Parse response object failed. "
														+ response);
									}
								}
							});
			List<RecipeItem> parseResponseTo = connector.parseResponseTo();
			return new LoaderState<List<RecipeItem>>(parseResponseTo);
		} catch (Exception e) {
			Log.e(TAG, url + " - " + e.getMessage(), e);
			return new LoaderState<List<RecipeItem>>(e);
		}
	}

	private int getStartIndex() {
		List<RecipeItem> cached = getCache().getCached(mKeyword);
		if (cached == null || cached.isEmpty()) {
			return 0;
		} else {
			return cached.size();
		}
	}

	private RecipeItemCache getCache() {
		return mCache;
	}

	public void setCache(RecipeItemCache cache) {
		this.mCache = cache;
	}

}
